#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <unordered_map>
#include <google/protobuf/map.h>
#include "../mqcommom/helper.hpp"
#include "../mqcommom/Log.hpp"
#include "../mqcommom/msg.pb.h"

/***************************
 * 交换机
 *      1.交换机名称 2.交换机类型(Type) 3.是否持久化 4.自动删除 5.其它参数map
 * 持久化管理，通过map快速定位数据库
 *      1.创建、删除表 2.新增交换机 3.移除交换机 4.查询某个交换机，查询所有交换机
 * 在内存中管理
 *      1.声明获取 2.移除某台机器 3.查询某台机器
 */
using namespace ns_helper;

namespace ns_rabbitmq
{
    class ExchangeMachine
    {
    public:
        using MachinePtr = std::shared_ptr<ExchangeMachine>;
        ExchangeMachine(const std::string &name, ExchangeType exchangetype, bool durable, bool autodelete,  const google::protobuf::Map<std::string, std::string> &args)
            : _name(name), _exchange_type(exchangetype), _durable(durable), _auto_delete(autodelete), _args(args)
        {
        }
        ExchangeMachine() {}
        // key=value&key=val
        void SetArgs(const std::string &str)
        {
            std::vector<std::string> substr;
            StrHelper::splite(str, "&", substr);
            // 按照=划分
            for (auto &str : substr)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                _args[key] = val;
            }
        }

        std::string GetArgs()
        {
            std::string result;
            for (auto start = _args.begin(); start != _args.end(); ++start)
                result += start->first + "=" + start->second + "&";
            if(result.size())
                result.pop_back();
            return result;
        }

    public:
        // 1.交换机名称
        std::string _name;
        // 2.交换机类型
        ExchangeType _exchange_type;
        // 3.是否持久化
        bool _durable;
        // 4.自动删除
        bool _auto_delete;
        // 5.其它参数
        google::protobuf::Map<std::string, std::string> _args;
    };

    // 基于map对数据库的操作
    class ExchangeMapper
    {
    public:
        using MachineMap = std::unordered_map<std::string, std::shared_ptr<ExchangeMachine>>;
        ExchangeMapper(const std::string &dbfile)
            : _sqlite_helper(dbfile)
        {
            // 1.获取父路径
            std::string path = FileHelper::ParentDirctory(dbfile);
            // 2.创建路径
            FileHelper::CreateDirctory(path);
            assert(_sqlite_helper.Open());
            CreateTable();
        }
        // 1.创建表
        void CreateTable()
        {
#define CREATE_TABLE "create table if not exists  exchange_table(\
                name varchar(20) primary key, \
                type int,\
                durable int ,\
                auto_delete int ,\
                args varchar(128));"
            bool exe = _sqlite_helper.Exec(CREATE_TABLE, nullptr, nullptr);
            if (!exe)
            {
                DLOG( "ExchangeMachine sqlite create fail!");
                abort();
            }
            std::cout << "创建成功!" << std::endl;
        }

        // 2.删除表
        void RemoveTable()
        {
#define DROP_TABLE "drop table if exists exchange_table;"
            bool ret = _sqlite_helper.Exec(DROP_TABLE, nullptr, nullptr);
            if (!ret)
            {
                DLOG("ExchangeMachine sqlite drop fail!");
                abort();
            }
        }
        // 3.新增交换机
        bool Insert(ExchangeMachine::MachinePtr &ptr)
        {
            std::stringstream ss;
            ss << "insert into exchange_table values(";
            ss << "'" << ptr->_name << "', ";
            ss << ptr->_exchange_type << ", ";
            ss << ptr->_durable << ", ";
            ss << ptr->_auto_delete << ", ";
            ss << "'" << ptr->GetArgs() << "');";
            bool ret = _sqlite_helper.Exec(ss.str(), nullptr, nullptr);
            if (!ret)
            {
                // lg.LogMessage(Error, "ExchangeMachine sqlite insert fail!");
                std::cout << "ExchangeMachine sqlite insert fail!" << std::endl;
                return false;
            }
            return true;
        }
        // 4.移除交换机
        bool RemoveMachine(const std::string &name)
        {
            std::string remove = "delete from exchange_table where name='";
            remove += name + "';";
            return _sqlite_helper.Exec(remove, nullptr, nullptr);
        }

        // 5.recovery形成<name,machine>
        MachineMap Recovery()
        {
            MachineMap machine_map;
            std::string sql = "select name, type, durable, auto_delete, args from exchange_table;";
            _sqlite_helper.Exec(sql, RecoveryCallback, &machine_map);
            return machine_map;
        }

    private:
        static int RecoveryCallback(void *args, int numcol, char **row, char **fields)
        {
            MachineMap *machine_map = static_cast<MachineMap *>(args);
            // 构建一台机器
            auto machine = std::make_shared<ExchangeMachine>();
            machine->_name = row[0];
            machine->_exchange_type = (ExchangeType)std::stoi(row[1]);
            machine->_durable = (bool)std::stoi(row[2]);
            machine->_auto_delete = (bool)std::stoi(row[3]);
            // 注意参数可能为空
            if (row[4])
                machine->SetArgs(row[4]);

            machine_map->insert(std::make_pair(machine->_name, machine));
            return 0;
        }

        SqliteHelper _sqlite_helper;
    };

    // 实际上，这个才是对外的接口
    //  内存中的交换机管理
    class ExchangeManager
    {
    public:
        using ExchangeManagerPtr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string &dbfile)
            : _exchange_mapper(dbfile)
        {
            // 如果不在内存中，就恢复
            _exchanges = _exchange_mapper.Recovery();
        }

        bool DeclareExchange(const std::string &name, ExchangeType exchangetype,
                             bool durable, bool autodelete, const  google::protobuf::Map<std::string, std::string>  &args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _exchanges.find(name);
            if (pos != _exchanges.end())
            {
                // 已经存在机器，就直接返回
                return true;
            }
            // 构建机器
            auto machine = std::make_shared<ExchangeMachine>(name, exchangetype, durable, autodelete, args);
            _exchanges.insert(std::make_pair(name, machine));
            if (durable)
                if (!_exchange_mapper.Insert(machine))
                    return false;
            return true;
        }

        // 删除交换机
        void DeleteExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _exchanges.find(name);
            if (pos == _exchanges.end())
            {
                // 不存在机器，就直接返回
                std::cout << "没找到" << std::endl;
                return;
            }
            _exchanges.erase(name);
            if (pos->second->_durable)
                _exchange_mapper.RemoveMachine(name);
        }
        // 获取指定交换机
        ExchangeMachine::MachinePtr SelectExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _exchanges.find(name);
            if (pos == _exchanges.end())
            {
                // 不存在机器，就直接返回
                return ExchangeMachine::MachinePtr();
            }
            return pos->second;
        }
        // 查询所有的交换机
        std::unordered_map<std::string, std::shared_ptr<ExchangeMachine>> SelectAll()
        {
            return _exchanges;
        }
        // 判断是否存在
        bool IsExistsMachine(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _exchanges.find(name);
            if (pos == _exchanges.end())
            {
                // 不存在机器，就直接返回
                return false;
            }
            return true;
        }

        // 删除所有交换机
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _exchanges.clear();
            _exchange_mapper.RemoveTable();
        }

        ssize_t Size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.size();
        }

    private:
        std::mutex _mutex;
        ExchangeMapper _exchange_mapper;
        std::unordered_map<std::string, std::shared_ptr<ExchangeMachine>> _exchanges;
    };
}